home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / MAILBOX.C < prev    next >
C/C++ Source or Header  |  1993-10-04  |  37KB  |  1,585 lines

  1. /* There are only two functions in this mailbox code that depend on the
  2.  * underlying protocol, namely mbx_getname() and dochat(). All the other
  3.  * functions can hopefully be used without modification on other stream
  4.  * oriented protocols than AX.25 or NET/ROM.
  5.  *
  6.  * SM0RGV 890506, most work done previously by W9NK
  7.  *
  8.  *** Changed 900114 by KA9Q to use newline mapping features in stream socket
  9.  *    interface code; everything here uses C eol convention (\n)
  10.  *
  11.  *    Numerous new commands and other changes by SM0RGV, 900120
  12.  */
  13. #include <stdio.h>
  14. #include <time.h>
  15. #include <ctype.h>
  16. #include <io.h>
  17. #include "global.h"
  18. #include "config.h"
  19. #include "timer.h"
  20. #include "mailbox.h"
  21. #include "cmdparse.h"
  22. #include "proc.h"
  23. #include "socket.h"
  24. #include "usock.h"
  25. #include "session.h"
  26. #include "ax25.h"
  27. #include "bbs.h"
  28. #include "dirutil.h"
  29. #include "telnet.h"
  30. #include "netrom.h"
  31. #include "commands.h"
  32. #include "netuser.h"
  33. #include "files.h"
  34. #include "server.h"
  35.  
  36. #ifdef MODEM
  37. #include "modem.h"
  38. #endif
  39.  
  40. #define MAX_MBXERR    3        /* a try to stop endless "Huh?" or "Error ?" */
  41. #define RETR_CMD     9
  42. #define STOR_CMD    10
  43.  
  44. struct mbx *Mbox = NULLMBX;
  45.  
  46. #undef UK
  47.  
  48. #ifdef UK
  49. int ThirdParty = 1;            /* default to thirdparty mail allowed */
  50. #endif
  51.  
  52. static char Banner[] = "[WNOS-H$]\n";
  53. static char Noperm[] = "Permission denied\n";
  54.  
  55. static char MHostname[30] = "\0";
  56. static char MBHostname[30] = "\0";
  57. static char MMotd[120] = "\0";
  58. static char Mbbanner[] = "%s%s TCP/IP system.";
  59. static char number[7];
  60. static char Loginbanner[] = "\nWNOS (%s)\n";
  61. static char Howtoend[] = "Terminate with /EX or ^Z in first column (^A aborts)\n";
  62. static char Aborted[] = "*** aborted\n";
  63. #ifdef NETROM
  64. static char mbnrid[20] = "\0";
  65. #endif
  66. #if (!defined(AX25) || defined(NETROM))
  67. static char Noserv[] = "Service unavailable\n";
  68. #endif
  69.  
  70. static void gw_alarm __ARGS((void *p));
  71. static int near mbx_getname __ARGS((struct mbx *m));
  72. static int near gw_connect __ARGS((struct mbx *m,int s,char *fsocket,int len));
  73. static void gw_input __ARGS((int s,void *notused,void *p));
  74. static void gw_superv __ARGS((int null,void *proc,void *p));
  75. static int near mbx_parse __ARGS((struct mbx *m));
  76.  
  77. static int domboxbye __ARGS((int argc,char **argv,void *p));
  78. static int dombhostname __ARGS((int argc,char **argv,void *p));
  79. static int dombescape __ARGS((int argc,char **argv,void *p));
  80. #ifdef AX25
  81. static int dombheard __ARGS((int argc,char **argv,void *p));
  82. #endif
  83. static int dodownload __ARGS((int argc,char **argv,void *p));
  84. static int dombupload __ARGS((int argc,char **argv,void *p));
  85. static int dombusermbx __ARGS((int argc,char **argv,void *p));
  86. static int dowhat __ARGS((int argc,char **argv,void *p));
  87. static int dosysop __ARGS((int argc,char **argv,void *p));
  88. static int dostars __ARGS((int argc,char **argv,void *p));
  89. static int dombhelp __ARGS((int argc,char **argv,void *p));
  90. static int dogateway __ARGS((int argc,char **argv,void *p));
  91. static int dombtelnet __ARGS((int argc,char **argv,void *p));
  92. #ifdef CONVERS
  93. static int dombconvers __ARGS((int argc,char **argv,void *p));
  94. #endif
  95. static int dombfinger __ARGS((int argc,char **argv,void *p));
  96. #ifdef AX25
  97. static int dombroute __ARGS((int argc,char **argv,void *p));
  98. #endif
  99. static int dombstat __ARGS((int argc,char **argv,void *p));
  100. #ifdef    NETROM
  101. static int dombnrconnect __ARGS((int argc,char **argv,void *p));
  102. static int dombnodes __ARGS((int argc,char **argv,void *p));
  103. #endif
  104. static int donothing __ARGS((int argc,char **argv,void *p));
  105.  
  106. static struct cmds near Mbcmds[] = {
  107.     "",            donothing,        0, 0, NULLCHAR,
  108.     "bye ",        domboxbye,        0, 0, NULLCHAR,
  109.     "bbs ",        dombbs,            0, 0, NULLCHAR,
  110.     "chat",        dogateway,        0, 0, NULLCHAR,
  111.     "connect",    dogateway,        0, 0, NULLCHAR,
  112. #ifdef CONVERS
  113.     "convers",    dombconvers,    0, 0, NULLCHAR,
  114. #endif
  115.     "download",    dodownload,        0, 2, "d[u] file",
  116.     "escape",    dombescape,        0, 0, NULLCHAR,
  117.     "exit",        domboxbye,        0, 0, NULLCHAR,
  118.     "finger",    dombfinger,        0, 0, NULLCHAR,
  119.     "help",        dombhelp,        0, 0, NULLCHAR,
  120.     "info",        dombhelp,        0, 0, NULLCHAR,
  121. #ifdef    AX25
  122.     "mheard",    dombheard,        0, 0, NULLCHAR,
  123. #endif
  124. #ifdef    NETROM
  125.     "nodes",    dombnodes,        0, 0, NULLCHAR,
  126.     "nconnect",    dombnrconnect,    0, 2, "nc call|node",
  127. #endif
  128. #ifdef AX25
  129.     "path",        dombroute,        0, 0, NULLCHAR,
  130. #endif
  131.     "quit",        domboxbye,        0, 0, NULLCHAR,
  132.     "telnet",    dombtelnet,        0, 2, "t host",
  133.     "user",        dombusermbx,    0, 0, NULLCHAR,
  134.     "upload",    dombupload,        0, 2, "u file",
  135.     "what",        dowhat,            0, 0, NULLCHAR,
  136.     "?   ",        dombhelp,        0, 0, NULLCHAR,
  137. /* cmds down here are not displayed by the "?" cmd */
  138.     "os",        dombstat,        0, 0, NULLCHAR,
  139.     "@",        dosysop,        0, 0, NULLCHAR,
  140.     "xr",        dombhostname,    0, 0, NULLCHAR,
  141.     "***",        dostars,        0, 0, NULLCHAR,
  142.     NULLCHAR,    NULLFP,            0, 0, "\n*** Error?\n",
  143. };
  144.  
  145. static int
  146. donothing(int argc,char **argv,void *p)
  147. {
  148.     return 0;
  149. }
  150.  
  151. static void near
  152. exitbbs(struct mbx *m)
  153. {
  154.     struct mbx *mcp, *mclast = NULLMBX;
  155.  
  156.     for(mcp = Mbox; mcp != NULLMBX; mclast = mcp, mcp = mcp->next) {
  157.         if(mcp == m) {
  158.             break;
  159.         }
  160.     }
  161.     if(mcp == NULLMBX) {
  162.         return;    /* Not found */
  163.     }
  164.     /* Remove from list */
  165.     if(mclast != NULLMBX) {
  166.         mclast->next = mcp->next;
  167.     } else {
  168.         Mbox = mcp->next;
  169.     }
  170.     if(m->path != NULLCHAR) {
  171.         xfree(m->path);
  172.     }
  173.     if(m->startmsg != NULLCHAR) {
  174.         xfree(m->startmsg);
  175.     }
  176.     xfree(m->line);
  177.     xfree(m);
  178. }
  179.  
  180. /* Incoming mailbox session */
  181. void
  182. mbx_incom(int s,void *t,void *p)
  183. {
  184.     struct mbx *m;
  185. #ifdef notused
  186.     struct usock *up;
  187. #endif
  188.     int rval;
  189.     char *cp, buf2[MAXPATH];
  190.     FILE *fp;
  191.  
  192.     sockowner(s,Curproc);                /* We own it now */
  193.     sockmode(s,SOCK_ASCII);
  194.  
  195.     close_s(Curproc->output);
  196.     close_s(Curproc->input);
  197.     Curproc->output = Curproc->input = s;
  198.  
  199.     m = mxallocw(sizeof(struct mbx));
  200.     m->next = Mbox;
  201.     Mbox = m;
  202.  
  203.     m->user = s;
  204.     setflush(m->user,-1);
  205.  
  206.     m->escape = 24;        /* default escape character is Ctrl-X */
  207.     m->type = (int)t;
  208.  
  209.     m->line = mxallocw(LINELEN);
  210.  
  211.     /* get the name of the remote station */
  212.     if(mbx_getname(m) == -1) {
  213.         goto quit;
  214.     }
  215.     m->state = MBX_CMD;    /* start in command state */
  216.  
  217.     if(userlogin(9980,0,m->name)) {
  218.         usputs(m->user,Banner);
  219.         usflush(m->user);
  220.         pause(5000);
  221.         dombbs(0x10,0,m);
  222.         goto quit;
  223.     }
  224. #ifdef NETROM
  225.     if(Nrifaces[0].alias != NULLCHAR) {
  226.         cp = strxdup(Nrifaces[0].alias);
  227.         if((cp1 = strchr(cp,' ')) != NULLCHAR)
  228.             *cp1 = '\0';
  229.         sprintf(mbnrid,"%s:%s> ",cp,pax25(m->line,Nrifaces[0].iface->hwaddr));
  230.         xfree(cp);
  231.     } else {
  232.         mbnrid[0] = '\0';
  233.     }
  234. #endif
  235.  
  236.     sprintf(MBHostname,"%.28s",Hostname);
  237.     if((cp = strchr(MBHostname,'.')) != NULLCHAR) {
  238.         *cp = '\0';
  239.     }
  240.     strlwr(MBHostname);
  241.  
  242.     /* Now say hi */
  243.     usprintf(m->user,Mbbanner,Banner,Hostname);
  244.  
  245.     sprintf(buf2,"%s/host.hlp",EtcRoot);
  246.  
  247.     if((fp = Fopen(buf2,READ_TEXT,0,0)) != NULLFILE) {
  248.         usputs(m->user,"\n");
  249.         sendfile(fp,m->user,ASCII_TYPE,0x80);
  250.     } else {
  251.         usputs(m->user," Type '?' for help.\n");
  252.     }
  253.     if(MMotd != NULLCHAR) {
  254.         usprintf(m->user,"%s\n",MMotd);
  255.     }
  256.     usprintf(m->user,"%s>\n",MBHostname);
  257.  
  258.     while(mbxrecvline(m) != EOF) {
  259.         if((rval = mbx_parse(m)) == -2) {
  260.             break;
  261.         }
  262.         if(rval == 1) {
  263.             usputs(m->user,"Bad syntax\n");
  264.         }
  265.         usprintf(m->user,"%s>",MBHostname);
  266.         m->state = MBX_CMD;
  267.     }
  268. quit:
  269.     exitbbs(m);
  270.  
  271. #ifdef notused
  272.     /* nasty hack! we may have screwed up reference count */
  273.     /* by invoking newproc("smtp_send",....); Fudge it!   */
  274.     if((up = itop(Curproc->output)) != NULLUSOCK) {
  275.         up->refcnt = 1;
  276.     }
  277. #endif
  278.     close_s(Curproc->output);
  279. }
  280.  
  281. /* "twocmds" defines the MBL/RLI two-letter commands, eg. "SB", "SP" and so on.
  282.  * They have to be treated specially since cmdparse() wants a space between
  283.  * the actual command and its arguments.
  284.  * "SP FOO" is converted to "s  foo" and the second command letter is saved
  285.  * in m->stype. Longer commands like "SEND" are unaffected, except for
  286.  * commands starting with "[", i.e. the SID, since we don't know what it will
  287.  * look like.
  288.  */
  289. static int near
  290. mbx_parse(struct mbx *m)
  291. {
  292.     int i;
  293.     char *cp, *newargv[2], twocmds[] = "d["; /* D is a two-letter command */
  294.  
  295.     /* Translate entire buffer to lower case */
  296.     strlwr(m->line);
  297.  
  298.     /* Skip any spaces at the begining */
  299.     for(cp = m->line; isspace(*cp); ++cp) ;
  300.  
  301.     m->stype = ' ';
  302.  
  303.     if(*cp != '\0' && *(cp+1) != '\0')
  304.         for(i = 0; i < strlen(twocmds); ++i) {
  305.             if(*cp == twocmds[i]
  306.               && (isspace(*(cp+2)) || *(cp+2) == '\0' || *cp == '[')) {
  307.                 m->stype = toupper(*++cp); /* Save the second character */
  308.                 *cp = ' ';
  309.                 break;
  310.             }
  311.         }
  312.  
  313.     /* See if the input line consists solely of digits */
  314.     for(cp = m->line; isspace(*cp); ++cp) ;
  315.  
  316.     newargv[1] = cp;
  317.     for( ; *cp != '\0' && isdigit(*cp); ++cp) ;
  318.  
  319.     if(*cp == '\0' && strlen(newargv[1]) > 0) {
  320.         return 0;
  321.     } else {
  322.         log(m->user,9981,m->line);        /* TEST */
  323.  
  324.         i = cmdparse(Mbcmds,m->line,(void *)m);
  325.         switch(i) {
  326.         case -3:
  327.             usputs(m->user,Noperm);
  328.             return 0;
  329.         case -2:
  330.             return -2;
  331.         case -1:
  332.             return (m->err_cnt++ >= MAX_MBXERR) ? -2 : -1;
  333.         default:
  334.             m->err_cnt = 0;
  335.             return i;
  336.         }
  337.     }
  338. }
  339.  
  340. static int near
  341. mbx_getname(struct mbx *m)
  342. {
  343.     union sp sp;
  344.     char *cp, tmp[MAXSOCKSIZE];
  345.     int oldmode, len = MAXSOCKSIZE;
  346.  
  347.     sp.p = tmp;
  348.     sp.sa->sa_family = AF_LOCAL;    /* default to AF_LOCAL */
  349.     getpeername(m->user,tmp,&len);
  350.     m->family = sp.sa->sa_family;
  351.  
  352.     /* This is one of the two parts of the mbox code that depends on the
  353.      * underlying protocol. We have to figure out the name of the
  354.      * calling station. This is only practical when AX.25 or NET/ROM is
  355.      * used. Telnet users have to identify themselves by a login procedure.
  356.      */
  357.     switch(m->family){
  358. #ifdef    AX25
  359.     case AF_NETROM:
  360.     case AF_AX25:
  361.         /* NETROM and AX25 socket address structures are "compatible" */
  362.         addrcp(m->nodename,sp.ax->ax25_addr);
  363.         m->nodename[ALEN] ^= 0x1e;
  364.         pax25(m->name,sp.ax->ax25_addr);
  365.  
  366.         if((cp = strchr(m->name,'-')) != NULLCHAR)
  367.             *cp = '\0';
  368.  
  369.         break;
  370. #endif
  371.     default:
  372.         m->state = MBX_LOGIN;
  373.         usprintf(m->user,Loginbanner,Hostname);
  374.         for(;;){
  375.             usputs(m->user,"Login (Call): ");
  376.  
  377.             if(mbxrecvline(m) == EOF) {
  378.                 return -1;
  379.             }
  380.             if(*m->line == '\0') {
  381.                 continue;
  382.             }
  383.             cp = m->line;
  384.             while(isspace(*cp)) {
  385.                 cp++;
  386.             }
  387.             sprintf(m->name,"%.19s",cp);
  388. #ifdef AX25
  389.             if(setcall(m->nodename,m->name) == -1)
  390.                 addrcp(m->nodename,Mycall);
  391.  
  392.             m->nodename[ALEN] ^= 0x1e;
  393. #else
  394.             m->nodename[0] = '\0';
  395. #endif
  396.             usprintf(m->user,"Password: %c%c%c",IAC,WILL,TN_ECHO);
  397.  
  398.             oldmode = sockmode(m->user,SOCK_BINARY);
  399.  
  400.             if(mbxrecvline(m) == EOF) {
  401.                 return -1;
  402.             }
  403.             usprintf(m->user,"%c%c%c",IAC,WONT,TN_ECHO);
  404.             sockmode(m->user,oldmode);
  405.             usputs(m->user,"\n");
  406.             usflush(m->user);
  407.             /* This is needed if the password was send before the
  408.              * telnet no-echo options were receied. We neeed to
  409.              * flush the eold sequence from the input buffers, sigh
  410.              */
  411.             if(socklen(m->user,0)) {        /* discard any remaining input */
  412.                 recv_mbuf(m->user,NULL,0,NULLCHAR,0);
  413.             }
  414.             break;
  415.         }
  416.         break;
  417.     }
  418.     /* Try to find the privileges of this user from the userfile */
  419.     userlogin(IPPORT_TELNET,(void *)m,m->line);
  420.  
  421.     log(m->user,9983,"NODE open %s %s",m->name,m->perms ? "" : m->line);
  422.  
  423.     /* SMTP wants the name to be in lower case */
  424.     strlwr(m->name);
  425.  
  426.     return (m->perms & EXCLUDED_CMD) ? -1 : 0;
  427. }
  428.  
  429. /* This works like recvline(), but telnet options are answered and the
  430.  * terminating newline character is not put into the buffer. If the
  431.  * incoming character equals the value of escape, any queued input is
  432.  * flushed and -2 returned.
  433.  */
  434. int
  435. mbxrecvline(struct mbx *m)
  436. {
  437.     int c, cnt = 0, opt;
  438.     char *buf = m->line;
  439.  
  440.     usflush(m->user);
  441.  
  442.     while((c = recvchar(m->user)) != -1) {
  443.         if(c == IAC) {        /* Telnet command escape */
  444.             if((c = recvchar(m->user)) == -1) {
  445.                 break;
  446.             }
  447.             if(c > 250 && c < 255 && (opt = recvchar(m->user)) != -1) {
  448. #ifdef XXX
  449.                 switch(c) {
  450.                 case WILL:
  451.                     usprintf(m->user,"%c%c%c",IAC,DONT,opt);
  452.                     break;
  453.                 case WONT:
  454.                     usprintf(m->user,"%c%c%c",IAC,DONT,opt);
  455.                     break;
  456.                 case DO:
  457.                     usprintf(m->user,"%c%c%c",IAC,WONT,opt);
  458.                     break;
  459.                 case DONT:
  460.                     usprintf(m->user,"%c%c%c",IAC,WONT,opt);
  461.                 }
  462.                 usflush(m->user);
  463. #endif
  464.                 continue;
  465.             }
  466.             if(c != IAC && opt == -1) {
  467.                 break;
  468.             }
  469.         }
  470.         /* ordinary character */
  471.         if(c == '\r' || c == '\n') {
  472.             break;
  473.         }
  474.         if(c == m->escape) {
  475.             if(socklen(m->user,0)) {        /* discard any remaining input */
  476.                 recv_mbuf(m->user,NULL,0,NULLCHAR,0);
  477.             }
  478.             cnt = -2;
  479.             break;
  480.         }
  481.         *buf++ = c;
  482.         if(++cnt > LINELEN - 2) {
  483.             break;
  484.         }
  485.     }
  486.     if(c == -1 && cnt == 0) {
  487.         return -1;
  488.     }
  489.     *buf = '\0';
  490.     return cnt;
  491. }
  492.  
  493. static int
  494. domboxbye(int argc,char **argv,void *p)
  495. {
  496.     struct mbx *m = (struct mbx *) p;
  497.  
  498.     /* Now say goodbye */
  499.     usputs(m->user,"73!\n");
  500.     usflush(m->user);
  501.     usflush(Curproc->output);
  502.     log(m->user,9983,"NODE close");
  503.     return -2;    /* signal that exitbbs() should be called */
  504. }
  505.  
  506. static int
  507. dombhelp(int argc,char **argv,void *p)
  508. {
  509.     struct mbx *m = (struct mbx *) p;
  510.  
  511.     if(argc < 2) {
  512.         int i;
  513.         struct cmds *cmdp;
  514.  
  515.         usputs(m->user,"\nAvailable commands:\n");
  516.  
  517.         for(i = 0, cmdp = Mbcmds; cmdp->name != NULLCHAR; cmdp++) {
  518.             if(strlen(cmdp->name) > 3) {
  519.                 usprintf(m->user,"%-15.15s%s",cmdp->name,(i == 4) ? "\n" : "");
  520.                 i = (i + 1) % 5;
  521.             }
  522.         }
  523.         if(i) {
  524.             usputs(m->user,"\n");
  525.         }
  526.     } else {
  527.         gethelp(9981,m->user,argv[1]);
  528.     }
  529.     return 0;
  530. }
  531.  
  532. #ifdef AX25
  533. static int
  534. dombroute(int argc,char **argv,void *p)
  535. {
  536.     if( argc < 2) {
  537.         struct mbx *m = (struct mbx *)p;
  538.         struct axroute_tab *rp;
  539.         int k = 0;
  540.         char tmp[AXBUF];
  541.  
  542.         usputs(m->user,"Destinations:\n");
  543.  
  544.         for(rp = Axroute_tab; rp; rp = rp->next) {
  545.             pax25(tmp,(char *)&rp->call);
  546.             usprintf(m->user,(k++ % 4) < 3 ? "%-20.19s" : "%s\n",tmp);
  547.         }
  548.         if(k % 4) {
  549.             usputs(m->user,"\n");
  550.         }
  551.     } else {
  552.         doroutelist(argc,argv,p);
  553.     }
  554.     return 0;
  555. }
  556. #endif
  557.  
  558. static int
  559. dombstat(int argc,char **argv,void *p)
  560. {
  561.     dostatus(9,0,p);
  562.     return 0;
  563. }
  564.  
  565. static int
  566. dombescape(int argc,char **argv,void *p)
  567. {
  568.     struct mbx *m = (struct mbx *)p;
  569.  
  570.     if(argc < 2){
  571.         usprintf(m->user,"The escape character is: CTRL-%c\n",m->escape+'A'-1);
  572.         return 0;
  573.     }
  574.     if(iscntrl(*argv[1])) {
  575.         m->escape = *argv[1];
  576.         return 0;
  577.     }
  578.     return 1;
  579. }
  580.  
  581. static int
  582. dodownload(int argc,char **argv,void *p)
  583. {
  584.     struct mbx *m = (struct mbx *)p;
  585.     char *file = pathname(m->path,argv[1]);
  586.  
  587.     if(!permcheck(m->path,m->perms,RETR_CMD,file)) {
  588.         xfree(file);
  589.         return -3;
  590.     } else {
  591.         FILE *fp;
  592.  
  593.         if(m->stype == 'U') {
  594.             if((fp = Fopen(file,READ_BINARY,m->user,0)) != NULLFILE) {
  595.                 /* uuencode a file -- translated from C++; both versions copyright 1990
  596.                  * by David R. Evans, G4AMJ/NQ0I
  597.                  */
  598.                 int n_read_so_far = 0, n_written_so_far = 0, in_chars, n, mode = 0755;
  599.                 unsigned long cnt = 0;
  600.                 static unsigned char in[3], out[4], line[100];
  601.  
  602.                 usprintf(m->user,"\nbegin %03o %s\n",mode,argv[1]);
  603.  
  604.                 /* do the encode */
  605.                 while((in_chars = fread(in,1,3,fp)) != 0) {
  606.                     out[0] = in[0] >> 2;
  607.                     out[1] = in[0] << 6;
  608.                     out[1] = out[1] >> 2;
  609.                     out[1] = out[1] | (in[1] >> 4);
  610.                     out[2] = in[1] << 4;
  611.                     out[2] = out[2] >> 2;
  612.                     out[2] = out[2] | (in[2] >> 6);
  613.                     out[3] = in[2] << 2;
  614.                     out[3] = out[3] >> 2;
  615.  
  616.                     for (n = 0; n < 4; n++) {
  617.                         out[n] += ' ';
  618.                     }
  619.                     n_read_so_far += in_chars;
  620.  
  621.                     for (n = 0; n < 4; n++) {
  622.                         line[n_written_so_far++] = out[n];
  623.                     }
  624.                     if ((in_chars != 3) || (n_written_so_far >= 60)) {
  625.                         line[(n_read_so_far + 2) / 3 * 4] = '\0';
  626.  
  627.                         if(usprintf(m->user,"%c%s\n",n_read_so_far + ' ', line) == EOF) {
  628.                             goto quit;
  629.                         }
  630.                         usflush(m->user);
  631.  
  632.                         cnt += n_read_so_far;
  633.                         n_read_so_far = 0;
  634.                         n_written_so_far = 0;
  635.                     }
  636.                 }
  637.                 usprintf(m->user," \nend\nsize %lu\n\n",cnt);
  638. quit:
  639.                 Fclose(fp);
  640.             }
  641.         } else {
  642.             if((fp = Fopen(file,READ_TEXT,m->user,0)) != NULLFILE) {
  643.                 sendfile(fp,m->user,ASCII_TYPE,0x80);
  644.             }
  645.         }
  646.     }
  647.     xfree(file);
  648.     return 0;
  649. }
  650.  
  651. static int near
  652. mbuser(int socket)
  653. {
  654.     int len, s;
  655.     char *cp, *cp1, fsocket[MAXSOCKSIZE], upl[40], down[40];
  656.     struct usock *up, *up1;
  657.  
  658.     struct mbx *m;
  659.  
  660. #ifdef AX25
  661.     char tmp[AXBUF];
  662. #endif
  663.  
  664. #ifdef NETROM
  665.     struct nrroute_tab *np;
  666.     char temp[AXBUF], *cp2, *cp3;
  667.     char circuit[] = "Circuit (%s%s %s)";
  668. #endif
  669.  
  670.     usputs(socket,"User:\n");
  671.  
  672.     for(m = Mbox; m != NULLMBX; m = m->next) {
  673.         len = MAXSOCKSIZE;
  674.         getpeername(m->user,fsocket,&len);
  675.         cp = strxdup(psocket(fsocket));
  676.  
  677.         *upl = '\0';
  678.         *down = '\0';
  679.  
  680.         switch(m->family) {        /* UPLINK */
  681. #ifdef AX25
  682.         case AF_AX25:
  683.             if((cp1 = strchr(cp,' ')) != NULLCHAR) {
  684.                 *cp1 = '\0';
  685.             }
  686.             sprintf(upl,"Uplink (%s)",cp);
  687.             break;
  688. #endif
  689. #ifdef NETROM
  690.         case AF_NETROM:
  691.             if((cp1 = strchr(cp,' ')) != NULLCHAR) {
  692.                 *cp1 = '\0';
  693.             }
  694.             cp1 += 3;
  695.             setcall(temp,cp1);
  696.  
  697.             if((np = find_nrroute(temp)) != NULLNRRTAB) {
  698.                 cp2 = strxdup(np->alias);
  699.             } else {
  700.                 cp2 = "";
  701.             }
  702.             if((cp3 = strchr(cp2,' ')) != NULLCHAR) {
  703.                 *cp3 = '\0';
  704.             }
  705.             if(isalnum(*cp2)) {
  706.                 strcat(cp2,":");
  707.             } else {
  708.                 *cp2 = '\0';
  709.             }
  710.             sprintf(upl,circuit,cp2,cp1,cp);
  711.             xfree(cp2);
  712.             break;
  713. #endif
  714.         case AF_INET:
  715.             if((cp1 = strchr(cp,':')) != NULLCHAR) {
  716.                 *cp1 = '\0';
  717.             }
  718.             sprintf(upl,"Telnet (%s)",cp);
  719.             break;
  720.         default:
  721.             strcpy(upl,"Connect");
  722.             break;
  723.         }
  724.         xfree(cp);
  725.         usprintf(socket,"%-36s",upl);
  726.  
  727.         for(s = SOCKBASE; s < Nusock + SOCKBASE; s++) {
  728.             if((up = itop(s)) == NULLUSOCK || s == m->user) {
  729.                 continue;
  730.             }
  731.             up1 = itop(m->user);
  732.  
  733.             if(up->owner == up1->owner) {
  734.                 getpeername(s,fsocket,&len);
  735.                 cp = strxdup(psocket(fsocket));
  736.                 switch(up->type) {
  737.                     case TYPE_TCP:
  738.                         if((cp1 = strchr(cp,':')) != NULLCHAR) {
  739.                             *cp1 = '\0';
  740.                         }
  741.                         sprintf(down,"Telnet (%s)",cp);
  742.                         break;
  743. #ifdef AX25
  744.                     case TYPE_AX25I:
  745.                         if((cp1 = strchr(cp,' ')) != NULLCHAR) {
  746.                             *cp1 = '\0';
  747.                         }
  748.                         sprintf(down,"Downlink (%s %s)",pax25(tmp,m->nodename),cp);
  749.                         break;
  750. #endif
  751. #ifdef NETROM
  752.                     case TYPE_NETROML4:
  753.                         if((cp1 = strchr(cp,' ')) != NULLCHAR) {
  754.                             *cp1 = '\0';
  755.                         }
  756.                         cp1 += 3;
  757.                         setcall(temp,cp1);
  758.                         np = find_nrroute(temp);
  759.                         cp2 = strxdup(np->alias);
  760.  
  761.                         if((cp3 = strchr(cp2,' ')) != NULLCHAR) {
  762.                             *cp3 = '\0';
  763.                         }
  764.                         addrcp(cp,m->nodename);
  765.                         cp[ALEN] ^= 0x1e;
  766.  
  767.                         if(isalnum(*cp2)) {
  768.                             strcat(cp2,":");
  769.                         } else {
  770.                             *cp2 = '\0';
  771.                         }
  772.                         sprintf(down,circuit,cp2,cp1,pax25(temp,cp));
  773.                         xfree(cp2);
  774.                         break;
  775. #endif
  776.                     default:
  777.                         strcpy(down,"Connect");
  778.                         break;
  779.                 }
  780.                 xfree(cp);
  781.                 usprintf(socket,"<-->  %s",down);
  782.                 break;
  783.             }
  784.         }
  785.     usputs(socket,"\n");
  786.     }
  787.     return 0;
  788. }
  789.  
  790. static int
  791. dombusermbx(int argc,char **argv,void *p)
  792. {
  793.     struct mbx *m = (struct mbx *)p;
  794.  
  795. #ifdef NETROM
  796.     if(m->family == AF_NETROM) {
  797.         usputs(m->user,mbnrid);
  798.     }
  799. #endif
  800.  
  801.     return mbuser(m->user);
  802. }
  803.  
  804. static int
  805. dombupload(int argc,char **argv,void *p)
  806. {
  807.     FILE *fp;
  808.     struct mbx *m = (struct mbx *)p;
  809.     char *file = pathname(m->path,argv[1]);
  810.  
  811.     if(!permcheck(m->path,m->perms,STOR_CMD,file)) {
  812.         xfree(file);
  813.         return -3;
  814.     } else if((fp = Fopen(file,WRITE_TEXT,m->user,1)) != NULLFILE) {
  815.         usprintf(m->user,"Send file. %s",Howtoend);
  816.  
  817.         for(;;) {
  818.             if(mbxrecvline(m) == EOF) {
  819.                 break;
  820.             }
  821.             if(*m->line == 0x01){  /* CTRL-A */
  822.                 unlink(file);
  823.                 usputs(m->user,Aborted);
  824.                 break;
  825.             }
  826.             if(*m->line == CTLZ
  827.               || !stricmp(m->line,"/ex")
  828.               || !stricmp(m->line,"***end")
  829.               || !strcmp(m->line,".")) {
  830.                 break;
  831.             }
  832.             fprintf(fp,"%s\n",m->line);
  833.         }
  834.         Fclose(fp);
  835.     }
  836.     xfree(file);
  837.     return 0;
  838. }
  839.  
  840. static int
  841. dowhat(int argc,char **argv,void *p)
  842. {
  843.     FILE *fp;
  844.     char *file;
  845.  
  846.     struct mbx *m = (struct mbx *)p;
  847.  
  848.     if(argc < 2) {
  849.         file = strxdup(m->path);
  850.     } else {
  851.         file = pathname(m->path,argv[1]);
  852.     }
  853.     if(!permcheck(m->path,m->perms,RETR_CMD,file)) {
  854.         xfree(file);
  855.         return -3;
  856.     } else if((fp = dir(file,1)) != NULLFILE) {
  857.         sendfile(fp,m->user,ASCII_TYPE,0x80);
  858.     }
  859.     xfree(file);
  860.     return 0;
  861. }
  862.  
  863. int
  864. dosysopset(int argc,char **argv,void *p)
  865. {
  866.     if(strlen(argv[1]) == 5 && atol(argv[1]) != 0) {
  867.         strcpy(number,argv[1]);
  868.     }
  869.     return 0;
  870. }
  871.  
  872. static int
  873. dosysop(int argc,char **argv,void *p)
  874. {
  875.     int c, i, k;
  876.     unsigned long int digit1[25], digit;
  877.  
  878.     struct mbx *m = (struct mbx *) p;
  879.  
  880.     if(!(m->perms & SYSOP_CMD)) {
  881.         return -3;
  882.     }
  883.     for(i=0; i<15; i++)    {
  884.         digit1[i] = random(10);
  885.         usprintf(m->user,"%d",digit1[i]);
  886.  
  887.         if(i == 4 || i == 9)
  888.             usputs(m->user,", ");
  889.     }
  890.     usputs(m->user,">");
  891.  
  892.     c = mbxrecvline(m);
  893.     if(c == EOF || c == -2)
  894.         return 0;
  895.  
  896.     if((digit = atol(number)) == 0)
  897.         digit = 22222;
  898.     digit1[15] = digit/10000;
  899.     digit -= digit1[15]*10000;
  900.     digit1[16] = digit/1000;
  901.     digit -= digit1[16]*1000;
  902.     digit1[17] = digit/100;
  903.     digit -= digit1[17]*100;
  904.     digit1[18] = digit/10;
  905.     digit -= digit1[18]*10;
  906.     digit1[19] = digit;
  907.  
  908.     for(i=0; i<3; i++) {
  909.         digit1[i+20] = 0;
  910.         for(k=0; k<5; k++)
  911.             digit1[i+20] += digit1[k+i*5] * digit1[k+15];
  912.     }
  913.     rip(m->line);
  914.  
  915.     if((digit = atol(m->line)) != 0
  916.       && (digit == digit1[20] || digit == digit1[21] || digit == digit1[22])) {
  917.         for(;;) {
  918.             usputs(m->user,"Net> ");
  919.             c = mbxrecvline(m);
  920.             if(c == EOF || c == -2)
  921.                 break;
  922.             log(m->user,9981,"SYSOP mode: %s",m->line);
  923.             cmdparse(Cmds,m->line,NULL);
  924.         }
  925.         return 0;
  926.     } else
  927.         return -3;
  928. }
  929.  
  930. static int
  931. dostars(int argc,char **argv,void *p)
  932. {
  933.     if(strcmp(argv[1],"error?") == 0) {
  934.         return -2;
  935.     }
  936.     return -1;
  937. }
  938.  
  939. #ifdef AX25
  940. static int
  941. dogateway(int argc,char **argv,void *p)
  942. {
  943.   extern int Attended;
  944.  
  945.   struct mbx *m = (struct mbx *)p;
  946.   struct sockaddr_ax fsocket, lsocket;
  947.   int s;
  948.   char *ap, path[10*AXALEN+1];
  949.   struct iface *ifp = NULLIF;
  950.   struct ax25_cb axp;
  951.  
  952.   if(argc < 2) {
  953.     if(Attended || (!Attended && *MHostname)) {
  954.       char buf[5], *newargv[3];
  955.  
  956.       newargv[0] = "telnet";
  957.       newargv[1] = (*MHostname) ? MHostname : Hostname;
  958.       sprintf(buf,"%d",IPPORT_TTYLINK);
  959.       newargv[2] = buf;
  960.       return dombtelnet(3,newargv,p);
  961.     } else {
  962.       char *name = strxdup(MBHostname);
  963.       strlwr(name);
  964.       usprintf(m->user,"OP is absent, pse enter the BBS and leave msg with 's %s'\n",name);
  965.       xfree(name);
  966.       return 0;
  967.     }
  968.   }
  969.   if(!(m->perms & AX25_CMD)) {
  970.     return -3;
  971.   }
  972.   argc--;
  973.   argv++;
  974.  
  975.   if((ifp = if_lookup(*argv)) != NULLIF) {
  976.     if(ifp->output != ax_output) {
  977.         usprintf(m->user,Badax,*argv);
  978.         return 0;
  979.     }
  980.     argc--;
  981.     argv++;
  982.   }
  983.   for(ap = path; argc > 0; argc--, argv++) {
  984.     if(!strncmp("via", *argv, strlen(*argv))) {
  985.       continue;
  986.     }
  987.     if(ap > path + sizeof(path) - 1) {
  988.       usputs(m->user,"Max 8 digis\n");
  989.       return 0;
  990.     }
  991.     if(setcall(ap, *argv)) {
  992.       usprintf(m->user,Invcall,*argv);
  993.       return 0;
  994.     }
  995.     ap[ALEN] &= ~E;
  996.  
  997.     if(ap == path) {
  998.       ap += AXALEN;
  999.       addrcp(ap,Mycall);
  1000.       ap[ALEN] &= ~E;
  1001.     }
  1002.     ap += AXALEN;
  1003.   }
  1004.   if(ap < path + 2 * AXALEN) {
  1005.     usputs(m->user,"Missing call\n");
  1006.     return 0;
  1007.   }
  1008.   ap[-1] |= E;
  1009.  
  1010.   memset(&axp,0,sizeof(struct ax25_cb));
  1011.  
  1012.   build_path(&axp,ifp,path,0);
  1013.  
  1014.   if(!axp.iface) {
  1015.     usputs(m->user,"No specified iface\n");
  1016.     return 0;
  1017.   }
  1018.  
  1019.   if(callreq(axp.path)) {
  1020.     char tmp[AXBUF];
  1021.     usprintf(m->user,Invcall,pax25(tmp,axp.path));
  1022.     return 0;
  1023.   }
  1024.  
  1025.   addrcp(axp.path + AXALEN,axp.iface->hwaddr);
  1026.   axroute_add(&axp,0);
  1027.  
  1028.   if((s = socket(AF_AX25,SOCK_STREAM,0)) == -1){
  1029.     usputs(m->user,Nosocket);
  1030.     return 0;
  1031.   }
  1032.  
  1033.   fsocket.sax_family = AF_AX25;
  1034.   addrcp(fsocket.ax25_addr,axp.path);
  1035.   memcpy(fsocket.iface,axp.iface->name,ILEN);
  1036.   m->startmsg = NULLCHAR;
  1037.  
  1038.   lsocket.sax_family = AF_AX25;
  1039.   addrcp(lsocket.ax25_addr,(*m->name == '\0') ? axp.iface->hwaddr : m->nodename);
  1040.   bind(s,(char *)&lsocket,SOCKSIZE);
  1041.   return gw_connect(m,s,(char *)&fsocket,SOCKSIZE);
  1042. }
  1043. #else
  1044. static int
  1045. dogateway(int argc,char **argv,void *p)
  1046. {
  1047.     extern int Attended;
  1048.  
  1049.     struct mbx *m = (struct mbx *) p;
  1050.  
  1051.     if(argc < 2) {
  1052.         if(Attended) {
  1053.             char buf[5], *newargv[3];
  1054.  
  1055.             newargv[0] = "telnet";
  1056.             newargv[1] = Hostname;
  1057.             sprintf(buf,"%d",IPPORT_TTYLINK);
  1058.             newargv[2] = buf;
  1059.             return dombtelnet(3,newargv,p);
  1060.         } else {
  1061.             char *name = strxdup(MBHostname);
  1062.             strlwr(name);
  1063.             usprintf(m->user,"OP is absent, pse enter the BBS and leave msg with 's %s'\n",name);
  1064.             xfree(name);
  1065.             return 0;
  1066.         }
  1067.     }
  1068.  
  1069.     usputs(m->user,Noserv);
  1070.     return 0;
  1071. }
  1072. #endif
  1073.  
  1074. static int
  1075. dombtelnet(int argc,char **argv,void *p)
  1076. {
  1077.     int s, len, i;
  1078.     char dsocket[MAXSOCKSIZE];
  1079.     struct sockaddr_in fsocket;
  1080.  
  1081.     struct mbx *m = (struct mbx *) p;
  1082.  
  1083.     fsocket.sin_family = AF_INET;
  1084.     fsocket.sin_port = (argc < 3) ? IPPORT_TELNET : atoi(argv[2]);
  1085.  
  1086.     if((fsocket.sin_addr.s_addr = resolve(argv[1])) == 0){
  1087.         usprintf(m->user,Badhost,argv[1]);
  1088.         return 0;
  1089.     }
  1090.     /* Only local telnets are are allowed to the unprivileged user */
  1091.     if(!(m->perms & TELNET_CMD) && !ismyaddr(fsocket.sin_addr.s_addr))
  1092.         return -3;
  1093.  
  1094.     if((s = socket(AF_INET,SOCK_STREAM,0)) == -1){
  1095.         usputs(m->user,Nosocket);
  1096.         return 0;
  1097.     }
  1098.     switch(fsocket.sin_port) {
  1099.     case IPPORT_TTYLINK:
  1100.         m->startmsg = mxallocw(80);
  1101.         len = MAXSOCKSIZE;
  1102.         i = getpeername(m->user,dsocket,&len);
  1103.         sprintf(m->startmsg,"*** Incoming call from %s@%s ***\n",
  1104.             m->name,(i != -1) ? psocket(dsocket) : Hostname);
  1105.         break;
  1106. #ifdef CONVERS
  1107.     case IPPORT_CONVERS:
  1108. /*
  1109.         if(m->startmsg == NULLCHAR) {
  1110.             m->startmsg = mxallocw(40);
  1111.             sprintf(m->startmsg,
  1112.                 "/n %s %d\n",m->name,(argc > 3) ? atoi(argv[3]) : 0);
  1113.         }
  1114. */
  1115.         m->state = MBX_CONVERS;
  1116.         break;
  1117. #endif
  1118.     }
  1119.     return gw_connect(m,s,(char *)&fsocket,SOCKSIZE);
  1120. }
  1121.  
  1122. static int
  1123. dombfinger(int argc,char **argv,void *p)
  1124. {
  1125.     struct mbx *m = (struct mbx *)p;
  1126.     char *host, *user = NULLCHAR, buf[8], *newargv[3];
  1127.  
  1128.     if(argc > 2) {
  1129.         usputs(m->user,"Usage: finger <user[@host]|@host>\n");
  1130.         return 0;
  1131.     }
  1132.     host = Hostname;
  1133.  
  1134.     if(argc == 2) {
  1135.         if((host = strchr(argv[1], '@')) != NULLCHAR) {
  1136.             *host = '\0';
  1137.             host++;
  1138.         } else {
  1139.             host = Hostname;
  1140.         }
  1141.         user = argv[1];
  1142.     }
  1143.     m->startmsg = mxallocw(80);
  1144.     sprintf(m->startmsg,"%s\n",user ? user : "");
  1145.     newargv[0] = "telnet";
  1146.     newargv[1] = host;
  1147.     sprintf(buf,"%d",IPPORT_FINGER);
  1148.     newargv[2] = buf;
  1149.  
  1150.     return dombtelnet(3,newargv,p);
  1151. }
  1152.  
  1153. #ifdef CONVERS
  1154. static int
  1155. dombconvers(int argc,char **argv,void *p)
  1156. {
  1157.     char *newargv[3], buf[6];
  1158.  
  1159.     newargv[0] = "telnet";
  1160.     newargv[1] = Hostname;
  1161.     sprintf(buf,"%d",IPPORT_CONVERS);
  1162.     newargv[2] = buf;
  1163.  
  1164.     return dombtelnet(3,newargv,p);
  1165. }
  1166. #endif
  1167.  
  1168. /* Generic mbox gateway code. It sends and frees the contents of m->startmsg
  1169.  * when the connection has been established unless it a null pointer.
  1170.  */
  1171. static int near
  1172. gw_connect(struct mbx *m,int s,char *fsocket,int len)
  1173. {
  1174.     int c;
  1175.     char *cp, *cp1, *node, buf[80];
  1176.     struct gwalarm *gwa;
  1177.     struct proc *child = newproc("gw supervisor",256,gw_superv,0,Curproc,m,0);
  1178.  
  1179.     sockmode(s,SOCK_ASCII);
  1180.  
  1181.     if(m->family == AF_AX25) {
  1182.         usputs(m->user,"link setup...\n");
  1183.         usflush(m->user);
  1184.     }
  1185.     node = strxdup(psocket((struct sockaddr *)fsocket));
  1186.  
  1187.     if((cp1 = strchr(node,' ')) != NULLCHAR)
  1188.         *cp1 = '\0';
  1189.  
  1190.     if(connect(s,fsocket,len) == -1) {
  1191.         if((cp = sockerr(s)) != NULLCHAR) {
  1192.             switch(cp[0]) {
  1193.             case 'R':
  1194. #ifdef NETROM
  1195.                 sprintf(buf,"%susy from",
  1196.                     (m->family == AF_NETROM) ? "B" : "*** b");
  1197. #else
  1198.                 sprintf(buf,"*** busy from");
  1199. #endif
  1200.                 break;
  1201.             case 'T':
  1202.                 if(m->family != AF_NETROM) {
  1203.                     sprintf(buf,"*** timeout with");
  1204.                     break;
  1205.                 }
  1206.             default:
  1207. #ifdef NETROM
  1208.                 sprintf(buf,"%sailure with",
  1209.                     (m->family == AF_NETROM) ? "F" : "*** f");
  1210. #else
  1211.                 sprintf(buf,"*** failure with");
  1212. #endif
  1213.                 break;
  1214.             }
  1215. #ifdef NETROM
  1216.             if(m->family == AF_NETROM)
  1217.                 usputs(m->user,mbnrid);
  1218. #endif
  1219.             usprintf(m->user,"%s %s\n",buf,node);
  1220.         }
  1221.         xfree(m->startmsg);
  1222.         m->startmsg = NULLCHAR;
  1223.         xfree(node);
  1224.         killproc(child);
  1225.         close_s(s);
  1226.         return 0;
  1227.     }
  1228. /*    log(Curproc->input,9981,"connect %s",node);    */
  1229.  
  1230. #ifdef NETROM
  1231.     if(m->family == AF_NETROM)
  1232.         usputs(m->user,mbnrid);
  1233.  
  1234.     usprintf(m->user,"%sonnected to %s\n",
  1235.         (m->family == AF_NETROM) ? "C" : "*** c", node);
  1236. #else
  1237.     usprintf(m->user,"*** connected to %s\n",node);
  1238. #endif
  1239.  
  1240.     xfree(node);
  1241.  
  1242.     /* The user did not type the escape character */
  1243.     killproc(child);
  1244.  
  1245.     if(m->startmsg != NULLCHAR) {
  1246.         usputs(s,m->startmsg);
  1247.         xfree(m->startmsg);
  1248.         m->startmsg = NULLCHAR;
  1249.     }
  1250.  
  1251.     /* Since NOS does not flush the output socket after a certain
  1252.      * period of time, we have to arrange that ourselves.
  1253.      */
  1254.     gwa = mxallocw(sizeof(struct gwalarm));
  1255.     stop_timer(&gwa->t);
  1256.     gwa->s1 = Curproc->output;
  1257.     gwa->s2 = s;
  1258.     gwa->t.func = gw_alarm;
  1259.     gwa->t.arg = gwa;
  1260.     set_timer(&gwa->t,240);            /* DB3FL */
  1261.     start_timer(&gwa->t);
  1262.  
  1263.     /* Fork off the receive process */
  1264.     child = newproc("gw in",1024,gw_input,s,m,Curproc,0);
  1265.  
  1266.     for(;;) {
  1267.         if((c = recvchar(Curproc->input)) == -1)
  1268.             break;
  1269.         if(c == m->escape) {
  1270.             if(socklen(Curproc->input,0)) {
  1271.                 recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0);
  1272.             }
  1273.             break;
  1274.         }
  1275.         if(usputc(s,c) == EOF)
  1276.             break;
  1277.     }
  1278.     stop_timer(&gwa->t);
  1279.     xfree(gwa);
  1280.     close_s(s);
  1281.     killproc(child); /* get rid of the receive process */
  1282.  
  1283.     if(m->family == AF_INET || m->family == AF_LOCAL) {
  1284.         usprintf(m->user,"%c%c%c\n",IAC,WONT,TN_ECHO);
  1285.     }
  1286.     return 0;
  1287. }
  1288.  
  1289. static void
  1290. gw_input(int s,void *notused,void *p)
  1291. {
  1292.     int c;
  1293.     char *cp;
  1294.  
  1295.     struct proc *parent = (struct proc *)p;
  1296.     struct mbx *m = (struct mbx *)notused;
  1297.  
  1298.     while((c = recvchar(s)) != EOF) {
  1299.         usputc(m->user,c);
  1300.     }
  1301.     if((cp = sockerr(s)) != NULLCHAR && m->family != AF_NETROM) {
  1302.         switch(*cp) {
  1303.         case 'T':
  1304.             usprintf(m->user,"\n*** %s: Link failure",MBHostname);
  1305.             break;
  1306.         case 'R':
  1307.             usputs(m->user,"*** DM received");
  1308.             break;
  1309.         }
  1310.     }
  1311. #ifdef NETROM
  1312.     if(m->family == AF_NETROM)
  1313.         usputs(m->user,mbnrid);
  1314. #endif
  1315.  
  1316.     usprintf(m->user,"\n%seconnected to %s\n",
  1317. #ifdef NETROM
  1318.         (m->family == AF_NETROM) ? "R" :
  1319. #endif
  1320.                                         "*** r",MBHostname);
  1321.  
  1322.     /* Tell the parent that we are no longer connected */
  1323.     alert(parent,(void *)ENOTCONN);
  1324.     pwait(Curproc); /* Now wait to be killed */
  1325. }
  1326.  
  1327. /* Check if the escape character is typed while the parent process is busy
  1328.  * doing other things.
  1329.  */
  1330. static void
  1331. gw_superv(int null,void *proc,void *p)
  1332. {
  1333.     int c;
  1334.     struct proc *parent = (struct proc *) proc;
  1335.     struct mbx *m = (struct mbx *) p;
  1336.  
  1337.     while((c = recvchar(Curproc->input)) != EOF)
  1338.         if(c == m->escape){
  1339.             /* flush anything in the input queue */
  1340.             if(socklen(Curproc->input,0))
  1341.                 recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0);
  1342.             break;
  1343.         }
  1344.     alert(parent,(void *)EINTR);    /* Tell the parent to quit */
  1345.     pwait(Curproc);                     /* Please kill me */
  1346. }
  1347.  
  1348. static void
  1349. gw_alarm(void *p)
  1350. {
  1351.     char oldbl;
  1352.     struct usock *up;
  1353.     struct gwalarm *gwa = (struct gwalarm *)p;
  1354.  
  1355.     /* Flush sockets s1 and s2, but first make sure that the socket
  1356.      * is set to non-blocking mode, to prevent the flush from blocking
  1357.      * if the high water mark has been reached.
  1358.      */
  1359.     if((up = itop(gwa->s1)) != NULLUSOCK) {
  1360.         oldbl = up->noblock;
  1361.         up->noblock = 1;
  1362.         usflush(gwa->s1);
  1363.         up->noblock = oldbl;
  1364.     }
  1365.     if((up = itop(gwa->s2)) != NULLUSOCK) {
  1366.         oldbl = up->noblock;
  1367.         up->noblock = 1;
  1368.         usflush(gwa->s2);
  1369.         up->noblock = oldbl;
  1370.     }
  1371.     start_timer(&gwa->t);
  1372. }
  1373.  
  1374. #ifdef AX25
  1375. static int
  1376. dombheard(int argc,char **argv,void *p)
  1377. {
  1378.     return doaxheard(argc,argv,p);
  1379. }
  1380. #endif
  1381.  
  1382. #ifdef    NETROM
  1383. static int
  1384. dombnodes(int argc,char **argv,void *p)
  1385. {
  1386.     int k = -1;
  1387.     struct mbx *m = (struct mbx *) p;
  1388.  
  1389.     if(!(m->perms & NETROM_CMD))
  1390.         return -3;
  1391.  
  1392.     if(Nrifaces[0].alias == NULLCHAR) {
  1393.         usputs(m->user,Noserv);
  1394.         return 0;
  1395.     }
  1396.  
  1397.     if(argc == 2)
  1398.         k = 9;
  1399.     if(argc > 1) {
  1400.         if(stricmp(argv[1],"tcp") == 0)
  1401.             k = 0;
  1402.         if(*argv[1] == '*')
  1403.             k = 10;
  1404.     }
  1405.     if(k != -1) {
  1406.         usprintf(m->user,"%sNodes:\n",(m->family == AF_NETROM) ? mbnrid : "");
  1407.         return doroutedump(k,0,p);
  1408.     }
  1409.     if(dorouteinfo(9,argv,p) == -1) {
  1410.         usprintf(m->user,"%s%so route to %s\n",
  1411.             (m->family == AF_NETROM) ? mbnrid : "",
  1412.             (m->family == AF_NETROM) ? "N" : "*** n",
  1413.             strupr(argv[1]));
  1414.         return -1;
  1415.     }
  1416.     return 0;
  1417. }
  1418.  
  1419. static int
  1420. dombnrconnect(int argc,char **argv,void *p)
  1421. {
  1422.     int s;
  1423.     struct sockaddr_nr lsocket, fsocket;
  1424.     char *np, alias[AXBUF];
  1425.  
  1426.     struct mbx *m = (struct mbx *) p;
  1427.  
  1428.     if((s = socket(AF_NETROM,SOCK_SEQPACKET,0)) == -1){
  1429.         usputs(m->user,Nosocket);
  1430.         return 0;
  1431.     }
  1432.     lsocket.nr_family = AF_NETROM;
  1433.  
  1434.     /* Set up our local username, bind would use Mycall instead */
  1435.     addrcp(lsocket.nr_addr.user,m->nodename);
  1436.     lsocket.nr_addr.user[ALEN] ^= 0x1e;
  1437.  
  1438.     /* Putting anything else than Mycall here will not work */
  1439.     addrcp(lsocket.nr_addr.node,Mycall);
  1440.     bind(s,(char *)&lsocket,SOCKSIZE);
  1441.  
  1442.     /* See if the requested destination could be an alias, and
  1443.      * find and use it if it is.  Otherwise assume it is an ax.25
  1444.      * address.
  1445.      */
  1446.     if(putalias(alias,argv[1],0) != -1 &&
  1447.         (np = find_nralias(alias)) != NULLCHAR){
  1448.         addrcp(fsocket.nr_addr.user,np);
  1449.         addrcp(fsocket.nr_addr.node,np);
  1450.     } else {    /* parse ax25 callsign */
  1451.         /* Only the user callsign of the remote station is never used by */
  1452.         /* NET/ROM, but it is needed for the psocket() call. */
  1453.         setcall(fsocket.nr_addr.user,argv[1]);
  1454.         setcall(fsocket.nr_addr.node,argv[1]);
  1455.     }
  1456.     fsocket.nr_family = AF_NETROM;
  1457.     return gw_connect(m,s,(char *)&fsocket,SOCKSIZE);
  1458. }
  1459. #endif
  1460.  
  1461.  
  1462. /* ---------------------------- Mbox subcmds ------------------------------ */
  1463. /* ------------------------------- begin ---------------------------------- */
  1464.  
  1465. static int
  1466. dombmotd(int argc,char **argv,void *p)
  1467. {
  1468.     if(argc < 2) {
  1469.         if(MMotd[0] != '\0')
  1470.             tputs(MMotd);
  1471.     } else {
  1472.         int i;
  1473.  
  1474.         *MMotd = '\0';
  1475.  
  1476.         for(i = 1; i < argc; i++) {
  1477.             strcat(MMotd,argv[i]);
  1478.             if(strlen(MMotd) > 110) {
  1479.                 break;
  1480.             }
  1481.             strcat(MMotd," ");
  1482.         }
  1483.         if(strlen(MMotd) > 2) {
  1484.             strcat(MMotd,"\n\0");
  1485.         } else {
  1486.             *MMotd = '\0';
  1487.         }
  1488.     }
  1489.     return 0;
  1490. }
  1491.  
  1492. static int
  1493. dombhostname(int argc,char **argv,void *p)
  1494. {
  1495.     struct mbx *m = (struct mbx *)p;
  1496.  
  1497.     if(*argv[0] == 'x') {
  1498.         if(!(m->perms & SYSOP_CMD)) {
  1499.             return -3;
  1500.         }
  1501.     }
  1502.     if(argc < 2) {
  1503.         if(*MHostname != '\0') {
  1504.             tprintf("%s\n",MHostname);
  1505.         }
  1506.     } else {
  1507.         sprintf(MHostname,"%.27s",argv[1]);
  1508.     }
  1509.     return 0;
  1510. }
  1511.  
  1512. static int
  1513. domboxdisplay(int argc,char **argv,void *p)
  1514. {
  1515.     struct mbx *m;
  1516.  
  1517.     static char fsocket[MAXSOCKSIZE], *states[] =
  1518.         {"LOGIN","CMD","BBS","CONVERS"};
  1519.  
  1520.     tputs("User       State    S#  Where\n");
  1521.  
  1522.     for(m = Mbox; m != NULLMBX; m = m->next) {
  1523.         int len = MAXSOCKSIZE;
  1524.         int j = getpeername(m->user,fsocket,&len);
  1525.         tprintf("%-11s%-9s%-4u%s\n",
  1526.             m->name,
  1527.             states[m->state],
  1528.             m->user,
  1529.             (j != -1) ? psocket(&fsocket) : "");
  1530.     }
  1531.     return 0;
  1532. }
  1533.  
  1534. #ifdef UK
  1535. /* if ThirdParty is not set - restrict the mailbox (S)end command to local only */
  1536. int
  1537. dombthirdparty(int argc,char **argv,void *p)
  1538. {
  1539.     return setbool(&ThirdParty,"Third-Party Mail",argc,argv);
  1540. }
  1541. #endif
  1542.  
  1543. #ifdef MODEM
  1544. static int
  1545. dotimeout(int argc,char **argv,void *p)
  1546. {
  1547.     return setuns(&Tiptimeout,"Tip conn timeout",argc,argv);
  1548. }
  1549. #endif
  1550.  
  1551. static int
  1552. dombusercon(int argc,char **argv,void *p)
  1553. {
  1554.     return mbuser(Curproc->output);
  1555. }
  1556.  
  1557. int
  1558. dombox(int argc,char **argv,void *p)
  1559. {
  1560.     /* mbox subcommand table */
  1561.     struct cmds Mbxsubcmd[] = {
  1562. #ifdef    AX25
  1563.         "finfo",        dofinfo,        0,       0, NULLCHAR,    /* in bbs.c */
  1564.         "fkick",        dofkick,        1024, 0, NULLCHAR,  /* in bbs.c */
  1565.         "fnic",            dofnic,            0,       0, NULLCHAR,  /* in bbs.c */
  1566. #endif
  1567.         "motd",            dombmotd,        0,    0, NULLCHAR,
  1568.         "remote",        dombhostname,    0,    0, NULLCHAR,
  1569.         "status",        domboxdisplay,    0,    0, NULLCHAR,
  1570. #ifdef UK
  1571.         "thirdparty",    dombthirdparty, 0,    0, NULLCHAR,
  1572. #endif
  1573. #ifdef MODEM
  1574.         "tiptimeout",    dotimeout,        0,    0, NULLCHAR,
  1575. #endif
  1576.         "user",            dombusercon,    0,    0, NULLCHAR,
  1577.         NULLCHAR,
  1578.     };
  1579.  
  1580.     return subcmd(Mbxsubcmd,argc,argv,p);
  1581. }
  1582.  
  1583. /* -------------------------------- end ----------------------------------- */
  1584. /* ---------------------------- Mbox subcmds ------------------------------ */
  1585.